package com.lagou.edu;

import com.lagou.edu.ioc.BeanPostProcessor;
import com.lagou.edu.ioc.stereotype.Autowired;
import com.lagou.edu.ioc.stereotype.Component;
import com.lagou.edu.ioc.stereotype.Transactional;
import com.lagou.edu.utils.TransactionManager;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by leon.L on 2020/1/9.
 * Desc : 声明式事务处理的 beanPostProcessor
 */
@Component
public class TransactionalPostProcessor implements BeanPostProcessor {

    @Autowired
    private TransactionManager transactionManager;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws Exception {
        Object resultObject = bean;
        Transactional transactional = bean.getClass().getAnnotation(Transactional.class);
        // 存在代理注解
        if (transactional != null) {
            // 是否有接口，有接口则选择 JDK 自带代理方式，否则使用 cglib 生成代理
            Class<?>[] interfaces = bean.getClass().getInterfaces();
            if (interfaces.length > 0) {
                // 使用 JDK 动态代理
                resultObject = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        return doProxyAction(bean, method, args);
                    }
                });
            } else {
                // 使用 cglib 生成代理对象
                resultObject = Enhancer.create(bean.getClass(), new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return doProxyAction(bean, method, objects);
                    }
                });


            }
        }
        return resultObject;
    }

    /**
     * 代理实现逻辑
     * @param beanObject 被代理的对象
     * @param method 被代理对象的方法
     * @param objects 方法参数
     * @return 方法执行返回值
     */
    private Object doProxyAction(Object beanObject, Method method, Object[] objects) throws Exception {
        // 事务控制代码
        Object result;
        try{

            // 开启事务(关闭事务的自动提交)
            transactionManager.beginTransaction();
            result = method.invoke(beanObject, objects);
            transactionManager.commit();
        }catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback();
            // 抛出异常便于上层servlet捕获
            throw e;
        }finally {
            //transactionManager.close();
        }
        return result;
    }
}
